package com.campus.counseling.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campus.counseling.entity.TestRecord;
import com.campus.counseling.entity.TestResult;
import com.campus.counseling.entity.SysUser;
import com.campus.counseling.entity.PsychologicalTest;
import com.campus.counseling.model.vo.TestQuestionVO;
import com.campus.counseling.model.common.exception.BusinessException;
import com.campus.counseling.model.dto.TestRecordDTO;
import com.campus.counseling.model.dto.TestResultDTO;
import com.campus.counseling.model.mapper.TestRecordMapper;
import com.campus.counseling.model.query.TestRecordQuery;
import com.campus.counseling.model.vo.TestResultVO;
import com.campus.counseling.scoring.ScoringEngine;
import com.campus.counseling.scoring.TotalScorer;
import com.campus.counseling.service.SysUserService;
import com.campus.counseling.service.TestRecordService;
import com.campus.counseling.service.TestResultService;
import com.campus.counseling.service.PsychologicalTestService;
import com.campus.counseling.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.time.LocalDateTime;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class TestRecordServiceImpl extends ServiceImpl<TestRecordMapper, TestRecord> implements TestRecordService {

    private final TestResultService testResultService;
    private final SysUserService userService;
    private final ScoringEngine scoringEngine;
    private final PsychologicalTestService testService;
    private final ObjectMapper objectMapper;

    @Override
    public Page<TestResultVO> getRecordPage(TestRecordQuery query) {
        // 获取当前用户信息
        Long currentUserId = SecurityUtils.getUserId();
        String userRole = SecurityUtils.getLoginUser().getRole();
        
        Page<TestRecord> page = new Page<>(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<TestRecord> wrapper = new LambdaQueryWrapper<>();
        
        // 根据角色设置查询权限
        if ("admin".equals(userRole) || "superadmin".equals(userRole)) {
            // 管理员可以查看所有记录
        } else if ("counselor".equals(userRole)) {
            // 咨询师可以查看所有已完成的测试记录
            wrapper.eq(TestRecord::getStatus, 1);  // 使用数字状态值
        } else {
            // 学生只能查看自己的记录
            wrapper.eq(TestRecord::getUserId, currentUserId);
        }
        
        // 如果有测试标题搜索条件
        if (StringUtils.hasText(query.getTestTitle())) {
            // 通过 mapper 查询匹配标题的测试ID
            List<Long> testIds = baseMapper.getTestIdsByTitle(query.getTestTitle());
            if (!testIds.isEmpty()) {
                wrapper.in(TestRecord::getTestId, testIds);
            } else {
                // 如果没找到匹配的测试，返回空结果
                return new Page<>();
            }
        }
        
        // 如果有评估等级搜索条件
        if (StringUtils.hasText(query.getLevel())) {
            // 通过关联查询匹配评估等级的记录
            wrapper.exists("SELECT 1 FROM test_result tr WHERE tr.record_id = test_record.id AND tr.level = {0}", query.getLevel());
        }
        
        // 其他查询条件
        if (query.getUserId() != null) {
            wrapper.eq(TestRecord::getUserId, query.getUserId());
        }
        if (query.getTestId() != null) {
            wrapper.eq(TestRecord::getTestId, query.getTestId());
        }
        if (query.getStatus() != null) {
            wrapper.eq(TestRecord::getStatus, query.getStatus());
        }
        
        wrapper.orderByDesc(TestRecord::getCreateTime);
        page = page(page, wrapper);
        
        return convertToVOPage(page);
    }

    @Override
    public TestResultVO getResultById(Long id) {
        TestRecord record = getById(id);
        if (record == null) {
            return null;
        }
        
        TestResult result = testResultService.getByRecordId(record.getId());
        if (result == null) {
            return null;
        }
        
        return convertToVO(record, result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long submitRecord(TestRecordDTO recordDTO) {
        // 获取现有记录
        TestRecord existingRecord = getById(recordDTO.getRecordId());
        if (existingRecord == null) {
            throw new RuntimeException("测试记录不存在");
        }

        // 更新记录
        existingRecord.setEndTime(LocalDateTime.now());
        existingRecord.setStatus(1); // 设置为已完成状态

        // 转换答案为List<Map<String, Object>>格式
        List<Map<String, Object>> formattedAnswers = recordDTO.getAnswers().entrySet().stream()
            .map(entry -> {
                Map<String, Object> answer = new HashMap<>();
                answer.put("questionId", Long.parseLong(entry.getKey()));
                answer.put("answer", entry.getValue());
                return answer;
            })
            .collect(Collectors.toList());
        existingRecord.setAnswers(formattedAnswers);
        
        // 转换答案Map用于计算分数
        Map<Long, String> answersForScoring = recordDTO.getAnswers().entrySet().stream()
            .collect(Collectors.toMap(
                entry -> Long.parseLong(entry.getKey()),
                Map.Entry::getValue
            ));
        
        // 计算维度得分
        Map<String, Double> dimensionScores = scoringEngine.calculateDimensionScores(
            recordDTO.getTestId(), answersForScoring);
        log.info("维度得分计算结果: {}", dimensionScores);
        
        // 计算总分
        Double totalScore = scoringEngine.calculateTotalScore(dimensionScores);
        log.info("总分计算结果: {}", totalScore);
        
        // 设置总分（四舍五入为整数）
        existingRecord.setTotalScore((int) Math.round(totalScore));
        updateById(existingRecord);
        
        // 获取初步评估结果
        Map<String, String> assessment = ((TotalScorer) scoringEngine).getAssessmentResult(totalScore);
        
        // 创建测试结果
        TestResult result = new TestResult();
        result.setRecordId(existingRecord.getId());
        result.setDimensionScores(testResultService.formatDimensionScores(dimensionScores));  // 将Map转换为JSON字符串
        result.setTotalScore(totalScore.intValue());  // 转换为Integer
        result.setLevel(assessment.get("level"));
        result.setAnalysis(assessment.get("analysis"));
        result.setSuggestions(assessment.get("suggestions"));
        testResultService.saveResult(result);
        
        return existingRecord.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void review(Long id, TestResultDTO dto) {
        // 获取测试结果
        TestResult result = testResultService.getById(id);
        if (result == null) {
            throw new RuntimeException("测试结果不存在");
        }

        // 获取评审人信息
        SysUser reviewer = userService.getById(dto.getReviewedBy());
        if (reviewer == null) {
            throw new RuntimeException("评审人不存在");
        }

        // 更新评审信息
        result.setReviewedBy(dto.getReviewedBy());
        result.setReviewComments(dto.getReviewComments());
        result.setReviewTime(LocalDateTime.now());

        // 保存更新
        if (!testResultService.updateById(result)) {
            throw new RuntimeException("更新测试结果失败");
        }
    }

    @Override
    public Map<String, Object> getAnswerRecord(Long id) {
        // 获取测试记录
        TestRecord record = getById(id);
        if (record == null) {
            throw new BusinessException("测试记录不存在");
        }

        // 获取答案记录
        String answers = baseMapper.getAnswersById(id);
        // 将答案字符串解析为List<Map>
        List<Map<String, Object>> answersList;
        try {
            if (answers != null) {
                answersList = objectMapper.readValue(answers, new TypeReference<List<Map<String, Object>>>() {});
            } else {
                answersList = new ArrayList<>();
            }
        } catch (Exception e) {
            log.error("解析答案失败", e);
            answersList = new ArrayList<>();
        }

        // 获取测试信息
        PsychologicalTest test = testService.getById(record.getTestId());
        if (test == null) {
            throw new BusinessException("测试不存在");
        }

        // 获取题目列表
        List<TestQuestionVO> questions = testService.getQuestions(test.getId());

        // 计算测试用时
        long duration = 0;
        if (record.getStartTime() != null && record.getEndTime() != null) {
            duration = Duration.between(record.getStartTime(), record.getEndTime()).toMinutes();
        }

        Map<String, Object> result = new HashMap<>();
        result.put("testTitle", test.getTitle());
        result.put("questions", questions);
        result.put("answers", answersList);
        result.put("duration", duration);

        return result;
    }

    private TestResultVO convertToVO(TestRecord record, TestResult result) {
        TestResultVO vo = new TestResultVO();
        BeanUtils.copyProperties(record, vo);
        BeanUtils.copyProperties(result, vo);
        
        // 设置测试标题
        if (record.getTestId() != null) {
            vo.setTestTitle(baseMapper.getTestTitleById(record.getTestId()));
        }
        
        // 设置用户信息
        if (record.getUserId() != null) {
            SysUser user = userService.getById(record.getUserId());
            if (user != null) {
                vo.setUsername(user.getUsername());
                log.info("Setting username: {} for user ID: {}", user.getUsername(), record.getUserId());
            }
        }
        
        // 设置评审人姓名
        if (result.getReviewedBy() != null) {
            vo.setReviewerName(userService.getById(result.getReviewedBy()).getRealName());
        }
        
        return vo;
    }

    private Page<TestResultVO> convertToVOPage(Page<TestRecord> page) {
        Page<TestResultVO> voPage = new Page<>();
        BeanUtils.copyProperties(page, voPage, "records");
        
        List<TestResultVO> voList = page.getRecords().stream()
            .map(record -> {
                TestResult result = testResultService.getByRecordId(record.getId());
                return result != null ? convertToVO(record, result) : null;
            })
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
        
        voPage.setRecords(voList);
        return voPage;
    }
} 